#include "ConfigManager.h"
#include "Yaml.hpp"

static int __StringTokenize(const std::string& input, const std::string& delimitor, std::vector<std::string>& output) {
    size_t token_begin;
    size_t token_end;

    output.clear();

    for (token_begin = token_end = 0; token_end != std::string::npos;) {
        token_begin = input.find_first_not_of(delimitor, token_begin);
        if (token_begin == std::string::npos)
            break;
        token_end = input.find_first_of(delimitor, token_begin + 1);
        output.push_back(input.substr(token_begin, token_end - token_begin));
        token_begin = token_end + 1;
    }

    return static_cast<int>(output.size());
}


Yaml::Node getNode(const Yaml::Node& node, const std::string& key) {
    std::vector<std::string> keys;
    __StringTokenize(key, ".", keys);

    Yaml::Node root = node;
    Yaml::Node result;
    for (const auto& keyNode : keys) {
        result = root[keyNode];
        root = result;
    }
    return result;
}

ConfigManager::ConfigManager() {
    mNode = nullptr;
}

ConfigManager::~ConfigManager() {
    if (mNode != nullptr) {
        delete (Yaml::Node*)mNode;
    }
}

bool ConfigManager::load_buffer(const std::string& buffer) {
    try {
        Yaml::Node* pNode = new Yaml::Node();
        mNode = pNode;

        Yaml::Parse(*pNode, buffer);
        std::cout << buffer << std::endl;

        return true;
    } catch (const std::exception & e) {
        printf("load config failed, data==%s, errmsg=%s\r\n", buffer.c_str(), e.what());
    }

    return false;
}

bool ConfigManager::load(const std::string& cfgFile) {

    try {
        Yaml::Node* pNode = new Yaml::Node();
        mNode = pNode;

        Yaml::Parse(*pNode, cfgFile.c_str());

        std::string output;
        Yaml::Serialize(*pNode, output);
        printf("%s\r\n%s\r\n", cfgFile.c_str(), output.c_str());

        return true;
    } catch (const std::exception& e) {
        printf("load config failed, path==%s, errmsg=%s\r\n", cfgFile.c_str(), e.what());
    }

    return false;

}

std::string& replace_all(std::string& str, const   std::string& old_value, const   std::string& new_value) {
    while (true) {
        std::string::size_type   pos(0);
        if ((pos = str.find(old_value)) != std::string::npos)
            str.replace(pos, old_value.length(), new_value);
        else
            break;
    }
    return   str;
}
uint32_t ConfigManager::GetInt(const std::string& key, uint32_t defValue) {

    std::string keyEnv = key;
    keyEnv = replace_all(keyEnv, ".", "_");
    char* pathvar = getenv(keyEnv.c_str());
    if (pathvar != nullptr) {
        defValue = atoi(pathvar);
    } else {
        try {
            Yaml::Node  node = getNode(*(Yaml::Node*)mNode, key);
            if (!node.IsNone()) {
                defValue = node.As<uint32_t>();
            }
        } catch (const std::exception & e) {
            printf("ConfigManager::GetInt key=%s, errmsg=%s\r\n", key.c_str(), e.what());
        }
    }
    printf("%s=%d\r\n", key.c_str(), defValue);
    return defValue;
}

std::string ConfigManager::GetString(const std::string& key, const std::string& defValue) {
    std::string retValue = defValue;
    std::string keyEnv = key;
    keyEnv = replace_all(keyEnv, ".", "_");
    char* pathvar = getenv(keyEnv.c_str());
    if (pathvar != nullptr) {
        retValue = pathvar;
    } else {
        try {
            Yaml::Node  node = getNode(*(Yaml::Node*)mNode, key);
            if (!node.IsNone()) {
                retValue = node.As<std::string>();
            }
        } catch (const std::exception & e) {
            printf("ConfigManager::GetString key=%s, errmsg=%s\r\n", key.c_str(), e.what());
        }
    }
    printf("%s=%s\r\n", key.c_str(), retValue.c_str());
    return retValue;
}

std::vector<uint32_t> ConfigManager::GetIntArray(const std::string& key) {
    std::vector<uint32_t> results;
    std::string keyEnv = key;
    keyEnv = replace_all(keyEnv, ".", "_");
    char* pathvar = getenv(keyEnv.c_str());
    if (pathvar != nullptr) {
        std::string pathKey = pathvar;
        std::vector < std::string> outs;
        __StringTokenize(pathKey, ",;", outs);

        for (size_t i = 0; i < outs.size(); i++) {
            results.push_back(atoi(outs[i].data()));
        }
    } else {
        try {
            Yaml::Node  node = getNode(*(Yaml::Node*)mNode, key);

            if (!node.IsNone()) {
                if (!node.IsNone()) {
                    if (node.IsSequence()) {
                        for (size_t i = 0; i < node.Size(); i++) {
                            results.push_back(node[i].As<uint32_t>());
                        }
                    } else if (node.IsScalar()) {

                        std::vector < std::string> outs;
                        __StringTokenize(node.As<std::string>(), ",;", outs);

                        for (size_t i = 0; i < outs.size(); i++) {
                            results.push_back(atoi(outs[i].data()));
                        }
                    }
                }
            }
        } catch (const std::exception & e) {
            printf("ConfigManager::GetIntArray key=%s, errmsg=%s\r\n", key.c_str(), e.what());
        }
    }

    printf("%s:\r\n", key.c_str());
    for (uint32_t i = 0; i < results.size(); i++) {
        printf("%d\r\n",   results[i]);
    }
    printf("\r\n");
    return results;
}

std::vector<std::string> ConfigManager::GetStringArray(const std::string& key) {
    std::vector<std::string> results;
    std::string keyEnv = key;
    keyEnv = replace_all(keyEnv, ".", "_");
    char* pathvar = getenv(keyEnv.c_str());
    if (pathvar != nullptr) {
        __StringTokenize(pathvar, ";", results);
    } else {
        try {
            Yaml::Node  node = getNode(*(Yaml::Node*)mNode, key);

            if (!node.IsNone()) {
                if (node.IsSequence()) {
                    for (size_t i = 0; i < node.Size(); i++) {
                        results.push_back(node[i].As<std::string >());
                    }
                } else if (node.IsScalar()) {
                    __StringTokenize(node.As<std::string>(), ";", results);
                }
            }
        } catch (const std::exception & e) {
            printf("ConfigManager::GetStringArray key=%s, errmsg=%s\r\n", key.c_str(), e.what());
        }
    }

    printf("%s:\r\n", key.c_str());
    for (uint32_t i = 0; i < results.size(); i++) {
        printf("%s\r\n",  results[i].c_str());
    }
    printf("\r\n");

    return results;
}




